package controller

import (
	rediscache "ahutoj/web/cache/redis"
	"ahutoj/web/io/constanct"
	"ahutoj/web/io/request"
	"ahutoj/web/io/response"
	"ahutoj/web/logic"
	"ahutoj/web/middlewares"
	"ahutoj/web/utils"
	"fmt"
	"strconv"

	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
)

// @Summary	添加比赛
// @Description
// @Tags		Contest
// @Accept		json
// @Produce	json
// @Param		AddContestReq	body		request.AddContestReq	true	"-"
// @Success	200				{object}	response.AddContestResp
// @Router		/api/contest/add/ [post]
func AddContest(ctx *gin.Context) {
	logger := utils.GetLogInstance()
	req := new(request.AddContestReq)
	if err := ctx.ShouldBindBodyWith(req, binding.JSON); err != nil {
		logger.Errorf("call ShouldBindWith failed,req:%+v, err = %s", utils.Sdump(req), err.Error())
		response.ResponseError(ctx, constanct.InvalidParamCode)
		return
	}
	resp, err := logic.AddContest(ctx, req)
	if err != nil {
		logger.Errorf("call AddContest failed, err = %s", err.Error())
		response.ResponseError(ctx, constanct.ServerErrorCode)
		return
	}
	response.ResponseOK(ctx, resp)
}

// @Summary	编辑比赛
// @Description
// @Tags		Contest
// @Accept		json
// @Produce	json
// @Param		EditContestReq	body		request.EditContestReq	true	"-"
// @Success	200				{object}	response.Response
// @Router		/api/contest/edit/ [post]
func EditContest(ctx *gin.Context) {
	logger := utils.GetLogInstance()
	req := new(request.EditContestReq)
	if err := ctx.ShouldBindBodyWith(req, binding.JSON); err != nil {
		logger.Errorf("call ShouldBindWith failed, err = %s", err.Error())
		response.ResponseError(ctx, constanct.InvalidParamCode)
		return
	}
	resp, err := logic.EditContest(ctx, req)
	if err != nil {
		logger.Errorf("call EditContest failed, err = %s", err.Error())
		response.ResponseError(ctx, constanct.ServerErrorCode)
		return
	}
	response.ResponseOK(ctx, resp)
}

// @Summary	删除比赛
// @Description
// @Tags		Contest
// @Accept		json
// @Produce	json
// @Param		DeleteContestReq	body		request.DeleteContestReq	true	"-"
// @Success	200					{object}	response.Response
// @Router		/api/contest/delete/ [post]
func DeleteContest(ctx *gin.Context) {
	logger := utils.GetLogInstance()
	req := new(request.DeleteContestReq)
	if err := ctx.ShouldBindBodyWith(req, binding.JSON); err != nil {
		logger.Errorf("call ShouldBindWith failed, err = %s", err.Error())
		response.ResponseError(ctx, constanct.InvalidParamCode)
		return
	}
	resp, err := logic.DeleteContest(ctx, req)
	if err != nil {
		logger.Errorf("call DeleteContest failed, err = %s", err.Error())
		response.ResponseError(ctx, constanct.ServerErrorCode)
		return
	}
	response.ResponseOK(ctx, resp)
}

// @Summary	获取比赛列表
// @Description
// @Tags		Contest
// @Accept		json
// @Produce	json
// @Param		ContestListReq	body		request.ContestListReq	true	"-"
// @Success	200				{object}	response.ContestListResp
// @Router		/api/contest/list [get]
func GetListContest(ctx *gin.Context) {
	logger := utils.GetLogInstance()
	req := new(request.ContestListReq)
	if err := ctx.ShouldBindWith(req, binding.Query); err != nil {
		logger.Errorf("call ShouldBindWith failed, err = %s", err.Error())
		response.ResponseError(ctx, constanct.InvalidParamCode)
		return
	}
	resp, err := logic.GetListContest(ctx, req)
	if err != nil {
		logger.Errorf("call GetListContest failed, err = %s", err.Error())
		response.ResponseError(ctx, constanct.ServerErrorCode)
		return
	}
	response.ResponseOK(ctx, resp)
}

// @Summary	获取比赛基础信息
// @Description
// @Tags		Contest
// @Accept		json
// @Produce	json
// @Param		Pass query string	true	"-"
// @Param		id				path		int						true	"CID"
// @Success	200				{object}	response.GetBaseContestResp
// @Router		/api/contest/base/{id}  [get]
func GetBaseContest(ctx *gin.Context) {
	logger := utils.GetLogInstance()
	req := new(request.GetBaseContestReq)
	CIDStr := ctx.Param("id")
	if CIDStr == "" {
		logger.Errorf("call Param failed,CID is empty")
		response.ResponseError(ctx, constanct.InvalidParamCode)
		return
	}

	CID, err := strconv.ParseInt(CIDStr, 10, 64)
	if err != nil {
		logger.Errorf("call strconv.ParseInt fialed,,req.CID:%v,err=%s", req.CID, err.Error())
		response.ResponseError(ctx, constanct.InvalidParamCode)
		return
	}
	req.CID = CID
	resp, err := logic.GetBaseContest(ctx, req)
	if err != nil {
		logger.Errorf("call GetBaseContest failed, err = %s", err.Error())
		response.ResponseError(ctx, constanct.ServerErrorCode)
		return
	}
	response.ResponseOK(ctx, resp)
}

// @Summary	获取比赛详情
// @Description
// @Tags		Contest
// @Accept		json
// @Produce	json
// @Param		Pass query string	true	"-"
// @Param		id				path		int						true	"CID"
// @Success	200				{object}	response.GetContestResp
// @Router		/api/contest/{id}  [get]
func GetContest(ctx *gin.Context) {
	logger := utils.GetLogInstance()
	req := new(request.GetContestReq)
	var err error
	err = ctx.ShouldBindWith(req, binding.Query)
	if err != nil {
		logger.Errorf("call ShouldBindWith failed, err=%s", err.Error())
		response.ResponseError(ctx, constanct.InvalidParamCode)
	}
	CIDStr := ctx.Param("id")
	if CIDStr == "" {
		logger.Errorf("call Param failed,CID is empty, err=%s", err.Error())
		response.ResponseError(ctx, constanct.InvalidParamCode)
		return
	}

	req.CID, err = strconv.ParseInt(CIDStr, 10, 64)
	if err != nil {
		logger.Errorf("call strconv.ParseInt fialed,,req.CID:%v,err=%s", req.CID, err.Error())
		response.ResponseError(ctx, constanct.InvalidParamCode)
		return
	}
	resp, err := logic.GetContest(ctx, req)
	if err != nil {
		logger.Errorf("call GetContest failed, err = %s", err.Error())
		response.ResponseError(ctx, constanct.ServerErrorCode)
		return
	}
	response.ResponseOK(ctx, resp)
}

// @Summary	获取比赛排名
// @Description
// @Tags		Contest
// @Accept		json
// @Produce	json
// @Param		GetContestReq	body		request.GetContestReq	true	"-"
// @Param		ContestListReq	body		request.ContestListReq	true	"-"
// @Param		UseWs			query		bool					true	"-"
// @Param		id				path		int							true	"CID"
// @Success	200					{object}	response.ContestRankRespWithAcm
// @Success	201					{object}	response.ConntestRankRespWithIOI
// @Router		/api/contest/{id}/rank [get]
func GetRankContest(ctx *gin.Context) {
	logger := utils.GetLogInstance()
	req := new(request.GetContestRankReq)
	CIDStr := ctx.Param("id")
	if CIDStr == "" {
		logger.Errorf("CID is empty")
		response.ResponseError(ctx, constanct.InvalidParamCode)
		return
	}
	var err error
	req.CID, err = strconv.ParseInt(CIDStr, 10, 64)
	if err != nil {
		logger.Errorf("call strconv.ParseInt fialed,err=%s", err.Error())
		response.ResponseError(ctx, constanct.InvalidParamCode)
		return
	}
	req.Pass = ctx.Query("Pass")
	resp, err := logic.GetRankContest(ctx, req)
	if err != nil {
		logger.Errorf("call GetRankContest failed, err = %s", err.Error())
		response.ResponseError(ctx, constanct.ServerErrorCode)
		return
	}
	response.ResponseOK(ctx, resp)
}

// @Summary	停止websocket排名流推送
// @Description
// @Tags		Contest
// @Accept		json
// @Produce	json
// @Param		id	path		int	true	"CID"
// @Success	200	{object}	response.Response
// @Router		/api/contest/{id}/rank [delete]
func DeleteWsRankClient(ctx *gin.Context) {
	logger := utils.GetLogInstance()
	CIDStr := ctx.Param("id")
	if CIDStr == "" {
		logger.Errorf("CID is empty")
		response.ResponseError(ctx, constanct.InvalidParamCode)
		return
	}
	CID, err := strconv.ParseInt(CIDStr, 10, 64)
	if err != nil {
		logger.Errorf("call strconv.ParseInt fialed,err=%s", err.Error())
		response.ResponseError(ctx, constanct.InvalidParamCode)
		return
	}
	UID := middlewares.GetUid(ctx)
	key := fmt.Sprintf("%v-%v", CID, UID)
	conn, exist := middlewares.GetConn(key)
	if exist {
		conn.Close()
		// middlewares.DeleteConn(key)
	} 
	// middlewares.DeleteRoomNews(key) //只有房间和连接都存在的dd
	// middlewares.DeleteRoom(key)     //只有房间没有连接的时候才会删除
	subch:=rediscache.GetRedisSubCh()
	room:=fmt.Sprintf("%v",CID)
	if stop, ok := subch[room]; ok {
		close(stop)
		delete(subch,room)
	}
	response.ResponseOK(ctx, response.CreateResponse(constanct.SuccessCode))
}

// @Summary	克隆比赛到题单
// @Description
// @Tags		Contest
// @Accept		json
// @Produce	json
// @Param		CloneContestReq	body		request.CloneContestReq	true	"-"
// @Success	200					{object}	response.CloneContestResp
// @Router		/api/contest/clone/ [post]
func CloneContest(ctx *gin.Context) {
	logger := utils.GetLogInstance()
	req := new(request.CloneContestReq)
	err := ctx.ShouldBindWith(req, binding.JSON)
	if err != nil {
		// 请求参数有误 直接返回响应CloneTrainUser
		logger.Errorf("call ShouldBindWith failed, err = %s", err.Error())
		response.ResponseError(ctx, constanct.InvalidParamCode)
		return
	}
	fmt.Printf("req:%+v\n", req)

	resp, err := logic.CloneContest(ctx, req)
	if err != nil {
		logger.Errorf("call CloneTrainUser failed,req=%+v,err=%s", *req, err.Error())
		response.ResponseError(ctx, constanct.ServerErrorCode)
		return
	}
	response.ResponseOK(ctx, resp)
}

// @Summary	更新比赛题目气球颜色🎈
// @Description 被迫营业
// @Tags		Contest
// @Accept		json
// @Produce	json
// @Param		UpdateConproColorReq	body		request.UpdateConproColorReq	true	"-"
// @Success	200					{object}	response.UpdateConproColorResp
// @Router		/api/contest/color/ [post]
func UpdateConproColor(ctx *gin.Context) {
	logger := utils.GetLogInstance()
	req := new(request.UpdateConproColorReq)
	err := ctx.ShouldBindWith(req, binding.JSON)
	if err != nil {
		// 请求参数有误 直接返回响应CloneTrainUser
		logger.Errorf("call ShouldBindWith failed, err = %s", err.Error())
		response.ResponseError(ctx, constanct.InvalidParamCode)
		return
	}
	// fmt.Printf("req:%+v\n", req)

	resp, err := logic.UpdateConproColor(ctx, req)
	if err != nil {
		logger.Errorf("call UpdateConproColor failed,req=%+v,err=%s", *req, err.Error())
		response.ResponseError(ctx, constanct.ServerErrorCode)
		return
	}
	response.ResponseOK(ctx, resp)
}

// @Summary	更新比赛题目分数
// @Description 被迫营业
// @Tags		Contest
// @Accept		json
// @Produce	json
// @Param		UpdateConproScoreReq	body		request.UpdateConproScoreReq	true	"-"
// @Success	200					{object}	response.UpdateConproScoreResp
// @Router		/api/contest/score/ [post]
func UpdateConproScore(ctx *gin.Context) {
	logger := utils.GetLogInstance()
	req := new(request.UpdateConproScoreReq)
	err := ctx.ShouldBindWith(req, binding.JSON)
	if err != nil {
		// 请求参数有误 直接返回响应CloneTrainUser
		logger.Errorf("call ShouldBindWith failed, err = %s", err.Error())
		response.ResponseError(ctx, constanct.InvalidParamCode)
		return
	}
	// fmt.Printf("req:%+v\n", req)

	resp, err := logic.UpdateConproScore(ctx, req)
	if err != nil {
		logger.Errorf("call UpdateConproScore failed,req=%+v,err=%s", *req, err.Error())
		response.ResponseError(ctx, constanct.ServerErrorCode)
		return
	}
	response.ResponseOK(ctx, resp)
}

// @Summary	获取比赛流推送排名
// @Description  最开始是全量榜，后面是变化的人的rankItem
// @Tags		Contest
// @Accept		json
// @Produce	json
// @Param		id	path		int	true	"-"
// @Success	200					{object}	response.Response
// @Router		/api/contest/{id}/rank/ws [post]
func GetWsRankClient(ctx *gin.Context){
	logger := utils.GetLogInstance()
	CIDStr := ctx.Param("id")
	if CIDStr == "" {
		logger.Errorf("CID is empty")
		return
	}
	CID, err := strconv.ParseInt(CIDStr, 10, 64)
	if err != nil {
		logger.Errorf("call strconv.ParseInt fialed,err=%s", err.Error())
		return
	}
	req:=request.GetWsRankClientReq{}
	req.CID=CID
	req.Pass=ctx.Query("Pass")
	logic.GetWsRankClient(ctx,&req)
}